/*******************************************************************************
 * Copyright (c) Jonathan Buck - jonbuck16@gmail.com
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    jonbuck16@gmail.com - initial API and implementation
 *******************************************************************************/
package net.jonbuck.tassoo.persistence.dao.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import net.jonbuck.tassoo.model.Attachment;
import net.jonbuck.tassoo.model.AttachmentType;
import net.jonbuck.tassoo.model.Categories;
import net.jonbuck.tassoo.model.Category;
import net.jonbuck.tassoo.model.Container;
import net.jonbuck.tassoo.model.Priorities;
import net.jonbuck.tassoo.model.Priority;
import net.jonbuck.tassoo.model.Status;
import net.jonbuck.tassoo.model.Statuses;
import net.jonbuck.tassoo.model.Task;
import net.jonbuck.tassoo.model.TassooPackage;
import net.jonbuck.tassoo.model.Type;
import net.jonbuck.tassoo.model.Types;
import net.jonbuck.tassoo.persistence.dao.TassooDao;
import net.jonbuck.tassoo.persistence.exception.TassooQueryException;
import net.jonbuck.tassoo.persistence.nl.Messages;

import org.apache.regexp.RE;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.query.conditions.eobjects.structuralfeatures.EObjectAttributeValueCondition;
import org.eclipse.emf.query.conditions.strings.StringRegularExpressionValue;
import org.eclipse.emf.query.conditions.strings.StringValue;
import org.eclipse.emf.query.statements.FROM;
import org.eclipse.emf.query.statements.IQueryResult;
import org.eclipse.emf.query.statements.SELECT;
import org.eclipse.emf.query.statements.WHERE;

/**
 * 
 * 
 * @since 1.0.0
 */
public class TassooDaoHelperUtil {

	/**
	 * <p>
	 * <b>Generates a list of currently defined attachment types for the user to
	 * select from.</b>
	 * </p>
	 * 
	 * @return
	 */
	public static String[] createTypeList(TassooDao tassooDao) {
		String[] attachmentTypes = null;
		if (tassooDao.isLoaded()) {
			int count = 0;
			List<String> existingTypes = new ArrayList<String>();
			for (AttachmentType type : tassooDao.getAttachmentTypes().getAttachmentType()) {
				if (!existingTypes.contains(type.getType())) {
					existingTypes.add(type.getType());
				}
			}
			attachmentTypes = new String[existingTypes.size()];
			for (String type : existingTypes) {
				attachmentTypes[count++] = type;
			}
		}
		return attachmentTypes;
	}

	/**
	 * 
	 * @param container
	 * @return
	 */
	public static Object[] getActiveTasks(TassooDao tassooDao, Container container) {
		String expression = null;
		for (Status status : tassooDao.getStatuses().getStatus()) {
			if (status.getAssociatedPercentage() == 100) {
				expression = "[^" + status.getValue() + "]";
			}
		}
		SELECT statement = new SELECT(new FROM(container), new WHERE(new EObjectAttributeValueCondition(
				TassooPackage.eINSTANCE.getTask_TaskName(), new StringRegularExpressionValue(expression))));
		IQueryResult result = statement.execute();
		if (result.getException() == null) {
			if (result.isEmpty()) {
				throw new TassooQueryException(Messages.exception_getactivetasks_noresults);
			}
		} else {
			throw new TassooQueryException(Messages.exception_getactivetasks_unknownexception, result.getException());
		}
		return result.toArray();
	}

	/**
	 * <p>
	 * <b>Determines the Icon to show for the attachment being passed in.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the <em>DAO</em> to use to retrieve data from the task store.
	 * @param attachment
	 *            the attachment to interrogate in order to determine which icon
	 *            to show.
	 * @return a path for the icon
	 */
	public static String getAttachmentImage(TassooDao tassooDao, Attachment attachment) {
		String returnImage = "/icons/apps/page_white.gif";
		if (tassooDao.isLoaded()) {
			for (AttachmentType type : tassooDao.getAttachmentTypes().getAttachmentType()) {
				if (type.getType().equals(attachment.getType()) && type.getSelectionExpression() != null) {
					if (new RE(type.getSelectionExpression()).match(attachment.getLocation())) {
						returnImage = type.getIcon();
					}
				}
			}
		}
		return returnImage;
	}

	/**
	 * 
	 * @param tassooDao
	 * @return
	 */
	public static String[] getCategoriesForCombo(TassooDao tassooDao) {
		int count = 0;
		Categories categories = tassooDao.getCategories();
		String[] categoryNames = new String[categories.getCategory().size()];
		for (Category category : categories.getCategory()) {
			categoryNames[count] = category.getValue();
			count++;
		}
		return categoryNames;
	}

	/**
	 * <p>
	 * <b>Queries the model and attempts to find and return the category whose
	 * value matches the value being passed in.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to return objects from the model
	 * @param value
	 *            the name of the category to find.
	 * @return the <code>Category</code> whose value matches the value being
	 *         passed in.
	 * @throws TassooQueryException
	 *             if the query being executed does not complete successfully,
	 *             the exception will contain a message and possibly and
	 *             <code>Exception</code> to help determine why the query
	 *             failed.
	 */
	public static Category getCategoryByValue(TassooDao tassooDao, String value) throws TassooQueryException {
		Category returnobj = null;
		SELECT statement = new SELECT(new FROM(tassooDao.getCategories()), new WHERE(new EObjectAttributeValueCondition(
				TassooPackage.eINSTANCE.getReferenceModel_Value(), new StringValue(value))));
		IQueryResult result = statement.execute();
		if (result.getException() == null) {
			if (result.isEmpty()) {
				throw new TassooQueryException(Messages.bind(Messages.exception_getcategorybyvalue_noresults, value));
			} else {
				if (result.size() > 1) {
					throw new TassooQueryException(Messages.bind(Messages.exception_getcategorybyvalue_toomanyresults, value));
				} else {
					Iterator<? extends EObject> objects = result.iterator();
					while (objects.hasNext()) {
						EObject object = objects.next();
						if (object instanceof Category) {
							returnobj = (Category) object;
							break;
						}
					}
				}
			}
		} else {
			throw new TassooQueryException(Messages.exception_getcategorybyvalue_unknownexception, result.getException());
		}
		return returnobj;
	}

	/**
	 * <p>
	 * <b>Queries the model and attempts to find the <code>Container</code>
	 * whose name matches the value being passed in.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to return objects from the model
	 * @param value
	 *            the name of the container to find.
	 * @return the container whose name matches the value being passed in.
	 * @throws TassooQueryException
	 *             if the query being executed does not complete successfully,
	 *             the exception will contain a message and possibly and
	 *             <code>Exception</code> to help determine why the query
	 *             failed.
	 */
	public static Container getContainerByValue(TassooDao tassooDao, String value) throws TassooQueryException {
		Container returnobj = null;
		SELECT statement = new SELECT(new FROM(tassooDao.getContainers()), new WHERE(new EObjectAttributeValueCondition(
				TassooPackage.eINSTANCE.getContainer_ContainerName(), new StringValue(value))));
		IQueryResult result = statement.execute();
		if (result.getException() == null) {
			if (result.isEmpty()) {
				throw new TassooQueryException(Messages.bind(Messages.exception_getcontainerbyvalue_noresults, value));
			} else {
				if (result.size() > 1) {
					throw new TassooQueryException(Messages.bind(Messages.exception_getcontainerbyvalue_toomanyresults, value));
				} else {
					Iterator<? extends EObject> objects = result.iterator();
					while (objects.hasNext()) {
						EObject object = objects.next();
						if (object instanceof Container) {
							returnobj = (Container) object;
							break;
						}
					}
				}
			}
		} else {
			throw new TassooQueryException(Messages.exception_getcontainerbyvalue_unknownexception, result.getException());
		}
		return returnobj;
	}

	/**
	 * 
	 * @param tassooDao
	 * @return
	 */
	public static String getDefaultCategory(TassooDao tassooDao) {
		Categories categories = tassooDao.getCategories();
		for (Category category : categories.getCategory()) {
			if (category.isDefault()) {
				return category.getValue();
			}
		}
		return null;
	}

	/**
	 * <p>
	 * <b>Identifies and returns the default priority.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to retrieve the data from the
	 *            task store.
	 * @return the default priority or null if the default priority cannot be
	 *         identified.
	 */
	public static String getDefaultPriority(TassooDao tassooDao) {
		Priorities priorities = tassooDao.getPriorities();
		for (Priority priority : priorities.getPriority()) {
			if (priority.isDefault()) {
				return priority.getValue();
			}
		}
		return null;
	}

	/**
	 * <p>
	 * <b>Iterates through the list of use defined status values and returns the
	 * value for the status marked as default.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to retrieve data from the model
	 * @return the value of the status that has been marked as the default
	 *         status.
	 */
	public static String getDefaultStatus(TassooDao tassooDao) {
		Statuses statuses = tassooDao.getStatuses();
		for (Status status : statuses.getStatus()) {
			if (status.isDefault()) {
				return status.getValue();
			}
		}
		return null;
	}

	/**
	 * <p>
	 * <b>Identifies and returns the default type.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to retrieve the data from the
	 *            task store.
	 * @return the default priority or null if the default priority cannot be
	 *         identified.
	 */
	public static String getDefaultType(TassooDao tassooDao) {
		Types types = tassooDao.getTypes();
		for (Type type : types.getType()) {
			if (type.isDefault()) {
				return type.getValue();
			}
		}
		return null;
	}

	/**
	 * 
	 * @param tassooDao
	 * @param container
	 */
	public static int getNextTaskId(TassooDao tassooDao, Container container) {
		int rValue = -1;
		for (Task task : container.getTask()) {
			if (task.getId() >= rValue) {
				rValue = task.getId() + 1;
			}
		}
		return rValue;
	}

	/**
	 * 
	 * @param tassooDao
	 * @return
	 */
	public static String[] getPrioritiesForCombo(TassooDao tassooDao) {
		int count = 0;
		Priorities priorities = tassooDao.getPriorities();
		String[] priorityNames = new String[priorities.getPriority().size()];
		for (Priority priority : priorities.getPriority()) {
			priorityNames[count] = priority.getValue();
			count++;
		}
		return priorityNames;
	}

	/**
	 * <p>
	 * <b>Queries the model and attempts to find and return the
	 * <code>Type</code> whose value matches the value being passed in.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to return objects from the model
	 * @param typeName
	 *            the name of the type to find.
	 * @return the <code>Type</code> whose value matches the value being passed
	 *         in.
	 * @throws TassooQueryException
	 *             if the query being executed does not complete successfully,
	 *             the exception will contain a message and possibly and
	 *             <code>Exception</code> to help determine why the query
	 *             failed.
	 */
	public static Priority getPriorityByValue(TassooDao tassooDao, String value) throws TassooQueryException {
		Priority returnobj = null;
		SELECT statement = new SELECT(new FROM(tassooDao.getPriorities()), new WHERE(new EObjectAttributeValueCondition(
				TassooPackage.eINSTANCE.getReferenceModel_Value(), new StringValue(value))));
		IQueryResult result = statement.execute();
		if (result.getException() == null) {
			if (result.isEmpty()) {
				throw new TassooQueryException(Messages.bind(Messages.exception_getprioritybyvalue_noresults, value));
			} else {
				if (result.size() > 1) {
					throw new TassooQueryException(Messages.bind(Messages.exception_getprioritybyvalue_toomanyresults, value));
				} else {
					Iterator<? extends EObject> objects = result.iterator();
					while (objects.hasNext()) {
						EObject object = objects.next();
						if (object instanceof Priority) {
							returnobj = (Priority) object;
							break;
						}
					}
				}
			}
		} else {
			throw new TassooQueryException(Messages.exception_getprioritybyvalue_unknownexception, result.getException());
		}
		return returnobj;
	}

	/**
	 * <p>
	 * <b>Searches the currently loaded task store for a <code>Status</code>
	 * object that matches the required percentage value and returns it to the
	 * caller.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            The <em>data access object</em> to use when retrieving data
	 *            from the task store.
	 * @param requiredPercentageValue
	 *            the percentage value that is required to return a status for
	 * @return the status that matches the required percentage value or null if
	 *         there isn't a status that matches.
	 */
	public static Status getStatusByPercentageValue(TassooDao tassooDao, int requiredPercentageValue) {
		Status rValue = null;
		if (tassooDao.isLoaded()) {
			for (Status status : tassooDao.getStatuses().getStatus()) {
				if (status.getAssociatedPercentage() == requiredPercentageValue) {
					rValue = status;
					break;
				}
			}
		}
		return rValue;
	}

	/**
	 * <p>
	 * <b>Queries the model and attempts to find and return the
	 * <code>Status</code> whose value matches the value being passed in.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to return objects from the model
	 * @param typeName
	 *            the name of the type to find.
	 * @return the <code>Type</code> whose value matches the value being passed
	 *         in.
	 * @throws TassooQueryException
	 *             if the query being executed does not complete successfully,
	 *             the exception will contain a message and possibly and
	 *             <code>Exception</code> to help determine why the query
	 *             failed.
	 */
	public static Status getStatusByValue(TassooDao tassooDao, String value) throws TassooQueryException {
		Status returnobj = null;
		SELECT statement = new SELECT(new FROM(tassooDao.getStatuses()), new WHERE(new EObjectAttributeValueCondition(
				TassooPackage.eINSTANCE.getReferenceModel_Value(), new StringValue(value))));
		IQueryResult result = statement.execute();
		if (result.getException() == null) {
			if (result.isEmpty()) {
				throw new TassooQueryException(Messages.bind(Messages.exception_getstatusbyvalue_noresults, value));
			} else {
				if (result.size() > 1) {
					throw new TassooQueryException(Messages.bind(Messages.exception_getstatusbyvalue_toomanyresults, value));
				} else {
					Iterator<? extends EObject> objects = result.iterator();
					while (objects.hasNext()) {
						EObject object = objects.next();
						if (object instanceof Status) {
							returnobj = (Status) object;
							break;
						}
					}
				}
			}
		} else {
			throw new TassooQueryException(Messages.exception_getstatusbyvalue_unknownexception, result.getException());
		}
		return returnobj;
	}

	/**
	 * <p>
	 * <b>Retrieves and constructs a <code>String[]</code> of statuses so that
	 * it can be used to populate Combo fields.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use return objects from the model.
	 * @return a <code>String[]</code> of status values that can be used to
	 *         populate a Combo field.
	 */
	public static String[] getStatusesForCombo(TassooDao tassooDao) {
		int count = 0;
		Statuses statuses = tassooDao.getStatuses();
		SortedSet<Status> tmpStatusNames = new TreeSet<Status>();
		for (Status status : statuses.getStatus()) {
			tmpStatusNames.add(status);
		}
		String[] statusList = new String[tmpStatusNames.size()];
		for (Object status : tmpStatusNames.toArray()) {
			Status currentStatus = (Status) status;
			statusList[count] = currentStatus.getValue();
			count++;
		}
		return statusList;
	}

	/**
	 * <p>
	 * <b>Queries the model and attempts to find and return the
	 * <code>Type</code> whose value matches the value being passed in.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to return objects from the model
	 * @param typeName
	 *            the name of the type to find.
	 * @return the <code>Type</code> whose value matches the value being passed
	 *         in.
	 * @throws TassooQueryException
	 *             if the query being executed does not complete successfully,
	 *             the exception will contain a message and possibly and
	 *             <code>Exception</code> to help determine why the query
	 *             failed.
	 */
	public static Task getTaskByValue(TassooDao tassooDao, Container container, String value) throws TassooQueryException {
		Task returnobj = null;
		SELECT statement = new SELECT(new FROM(container), new WHERE(new EObjectAttributeValueCondition(
				TassooPackage.eINSTANCE.getTask_TaskName(), new StringValue(value))));
		IQueryResult result = statement.execute();
		if (result.getException() == null) {
			if (result.isEmpty()) {
				throw new TassooQueryException(Messages.bind(Messages.exception_gettaskbyvalue_noresults, value));
			} else {
				if (result.size() > 1) {
					throw new TassooQueryException(Messages.bind(Messages.exception_gettaskbyvalue_toomanyresults, value));
				} else {
					Iterator<? extends EObject> objects = result.iterator();
					while (objects.hasNext()) {
						EObject object = objects.next();
						if (object instanceof Task) {
							returnobj = (Task) object;
							break;
						}
					}
				}
			}
		} else {
			throw new TassooQueryException(Messages.exception_gettaskbyvalue_unknownexception, result.getException());
		}
		return returnobj;
	}

	/**
	 * <p>
	 * <b>Queries the model and attempts to find and return the
	 * <code>Type</code> whose value matches the value being passed in.</b>
	 * </p>
	 * 
	 * @param tassooDao
	 *            the data access object to use to return objects from the model
	 * @param value
	 *            the name of the type to find.
	 * @return the <code>Type</code> whose value matches the value being passed
	 *         in.
	 * @throws TassooQueryException
	 *             if the query being executed does not complete successfully,
	 *             the exception will contain a message and possibly and
	 *             <code>Exception</code> to help determine why the query
	 *             failed.
	 */
	public static Type getTypeByValue(TassooDao tassooDao, String value) throws TassooQueryException {
		Type returnobj = null;
		if (tassooDao.isLoaded()) {
			SELECT statement = new SELECT(new FROM(tassooDao.getTypes()), new WHERE(new EObjectAttributeValueCondition(
					TassooPackage.eINSTANCE.getReferenceModel_Value(), new StringValue(value))));
			IQueryResult result = statement.execute();
			if (result.getException() == null) {
				if (result.isEmpty()) {
					throw new TassooQueryException(Messages.bind(Messages.exception_gettypebyvalue_noresults, value));
				} else {
					if (result.size() > 1) {
						throw new TassooQueryException(Messages.bind(Messages.exception_gettypebyvalue_toomanyresults, value));
					} else {
						Iterator<? extends EObject> objects = result.iterator();
						while (objects.hasNext()) {
							EObject object = objects.next();
							if (object instanceof Type) {
								returnobj = (Type) object;
								break;
							}
						}
					}
				}
			} else {
				throw new TassooQueryException(Messages.exception_gettypebyvalue_unknownexception, result.getException());
			}
		}
		return returnobj;
	}

	/**
	 * 
	 * @param tassooDao
	 * @return
	 */
	public static String[] getTypesForCombo(TassooDao tassooDao) {
		int count = 0;
		Types types = tassooDao.getTypes();
		String[] typeNames = new String[types.getType().size()];
		for (Type type : types.getType()) {
			typeNames[count] = type.getValue();
			count++;
		}
		return typeNames;
	}
}
